﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using EnvDTE80;
using DesignPatternToolkit.Wizard.WizardPages;
using DesignPatternToolkit.Wizard.Engine;
using System.IO;
using System.Reflection;
using DesignPatternToolkit.Wizard.Helpers;
using System.CodeDom;
using EnvDTE;
using System.CodeDom.Compiler;

namespace DesignPatternToolkit.Wizard
{
    public partial class PatternWizardMain : Form
    {
        private List<WizardPageBase> _wizardPages = new List<WizardPageBase>();
        private WizardPageBase _currentPage;

        public PatternWizardMain(DTE visualStudioInst)
            : this()
        {
            WizardConfiguration.Instance.VisualStudioEnv = visualStudioInst;

            // Check to see if we have any projects loaded yet.
            Solution solution = visualStudioInst.Solution;
            if (solution == null || solution.Projects.Count == 0)
            {
                MessageBox.Show("You haven't loaded any projects yet. Please open a project and try again.", "No projects...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Close();
            }
        }

        public PatternWizardMain()
        {
            InitializeComponent();

            // See if we have any patterns available by looking them up in the directory.
            WizardConfiguration.Instance.AvailablePatterns = LukeFileWalker.GetAvailablePatterns();

            navigationControls.NextButtonClicked += new EventHandler(OnNextButtonClicked);
            navigationControls.PreviousButtonClicked += new EventHandler(OnPreviousButtonClicked);

            // Add the pages we will be using.
            _wizardPages.Add(new Welcome());
            _wizardPages.Add(new PatternSelector());
            _wizardPages.Add(new ConfigurationProperties());
            _wizardPages.Add(new ProjectSelector());
            _wizardPages.Add(new Finish());

            // Start off with Welcome!
            SetCurrentPage(_wizardPages[0]);

            // Initially hide the previous button.
            navigationControls.PreviousButtonVisible = false;
        }

        /// <summary>
        /// Sets the current page in the wizard.
        /// </summary>
        /// <param name="page">An instance of <see cref="WizardPageBase"/>.</param>
        private void SetCurrentPage(WizardPageBase page)
        {
            try
            {
                if (_currentPage != null)
                {
                    _currentPage.BeforeUnload();
                    panelContent.Controls.Remove(_currentPage);
                }

                _currentPage = page;
                _currentPage.Dock = DockStyle.Fill;
                panelContent.Controls.Add(page);

                navigationControls.PreviousButtonVisible = _currentPage.PreviousButtonVisible;
                navigationControls.NextButtonVisible = _currentPage.NextButtonVisible;

                navigationControls.SetTextNextButton(_currentPage.NextButtonText);
                navigationControls.SetTextPreviousButton(_currentPage.PreviousButtonText);

                _currentPage.BeforeLoad();

            }
            catch (ApplicationException aex)
            {
                MessageBox.Show(aex.Message, "Oeps...", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                string message = "An exception occured that we could see coming but didn't catch properly.";
                message += Environment.NewLine;
                message += "Please review the exception message below.";
                message += Environment.NewLine;
                message += Environment.NewLine;
                message += ex.Message;
                MessageBox.Show(message, "Major oeps...", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
 
        /// <summary>
        /// Sets the next page.
        /// </summary>
        private void SetNextPage()
        {
            if (!_currentPage.IsFinalPage)
            {
                int currIndex = _wizardPages.IndexOf(_currentPage);
                SetCurrentPage(_wizardPages[currIndex + 1]);
            }
            else
            {
                CreateSomeFunkyCode();
            }
        }

        /// <summary>
        /// Sets the previous page.
        /// </summary>
        private void SetPreviousPage()
        {
            int currIndex = _wizardPages.IndexOf(_currentPage);
            SetCurrentPage(_wizardPages[currIndex - 1]);
        }

        /// <summary>
        /// Eventhandler for the Previous button in the navigation controls.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnPreviousButtonClicked(object sender, EventArgs e)
        {
            SetPreviousPage();
        }

        /// <summary>
        /// Eventhandler for the Next button in the navigation controls.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnNextButtonClicked(object sender, EventArgs e)
        {
            SetNextPage();
        }

        /// <summary>
        /// Actually calles the selected PatternBuilder and have it create the code.
        /// </summary>
        private void CreateSomeFunkyCode()
        {
            // Actually create the code!
            List<System.CodeDom.CodeNamespace> codeFiles = WizardConfiguration.Instance.PatternBuilder.CreateClasses();

            // All generated code come in CodeNamespace objects.
            foreach (System.CodeDom.CodeNamespace codeFile in codeFiles)
            {
                Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();

                /* Get the classname and the file extension to build the actual file. */
                string className = codeFile.Types[0].Name;
                string fileName = string.Format("{0}.{1}", className, provider.FileExtension);

                // The DteHelper helps us working with the IDE.
                DteHelper dteHelper = null;
                string projectLocation = string.Empty;
                string classFileName = string.Empty;

                // If we're working with SharpDevelop, you don't have an instance of Visual Studio.
                if (WizardConfiguration.Instance.VisualStudioEnv != null)
                {
                    dteHelper = new DteHelper(WizardConfiguration.Instance.VisualStudioEnv);
                    projectLocation = Path.GetDirectoryName(dteHelper.GetProjectRefByName(WizardConfiguration.Instance.ProjectName).FullName);
                }
                else
                {
                    projectLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                }
                classFileName = Path.Combine(projectLocation, fileName);

                /* Create a textwriter object for the codegeneretor to write the class to. */
                using (TextWriter tw = File.CreateText(classFileName))
                {
                    CodeGeneratorOptions options = new CodeGeneratorOptions();
                    options.BlankLinesBetweenMembers = true;
                    options.BracingStyle = "C";

                    /* Create the file. */
                    provider.GenerateCodeFromNamespace(codeFile, tw, options);

                    tw.Close();
                }

                if (WizardConfiguration.Instance.VisualStudioEnv != null)
                {
                    /* And add the file to the selected project. */
                    dteHelper.AddProjectItem(dteHelper.GetProjectRefByName(WizardConfiguration.Instance.ProjectName), new FileInfo(classFileName));
                }
            }

            // Our work is done.
            Close();
        }
    }
}
